using System;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

namespace Taco.Timeline
{
    [ScriptGuid("3f0d14cafa6f2c84389c42789ec00083"), IconGuid("e6435fa591ae4414eb0f26dc6410086e"), Ordered(0), Color(127, 253, 228)]
    public class AnimationTrack : Track<TimelineAnimationClipPlayable>
    {
        static AvatarMask s_FullBodyMask;
        public static AvatarMask FullBodyMask
        {
            get
            {
                if (s_FullBodyMask == null)
                {

                    s_FullBodyMask = new AvatarMask();
                    for (int i = 0; i < 13; i++)
                    {
                        s_FullBodyMask.SetHumanoidBodyPartActive((AvatarMaskBodyPart)i, true);
                    }
                }
                return s_FullBodyMask;
            }
        }


        [ShowInInspector, OnValueChanged("RebindTimeline")]
        public AvatarMask AvatarMask;

        public override void Bind()
        {
            TrackPlayable = AnimationMixerPlayable.Create(Timeline.PlayableGraph, Clips.Count);
            base.Bind();
            if (AvatarMask)
                Timeline.RootPlayable.SetLayerMaskFromAvatarMask((uint)PlayableIndex, AvatarMask);
            else
                Timeline.RootPlayable.SetLayerMaskFromAvatarMask((uint)PlayableIndex, FullBodyMask);
        }

#if UNITY_EDITOR
        public override Type ClipType => typeof(AnimationClip);

        public override Clip AddClip(UnityEngine.Object referenceObject, int frame)
        {
            AnimationClip clip = new AnimationClip(referenceObject as UnityEngine.AnimationClip, this, frame);
            m_Clips.Add(clip);
            return clip;
        }
        public override bool DragValid()
        {
            return UnityEditor.DragAndDrop.objectReferences.Length == 1 && UnityEditor.DragAndDrop.objectReferences[0] as UnityEngine.AnimationClip;
        }

#endif
    }

    [ScriptGuid("3f0d14cafa6f2c84389c42789ec00083"), Color(127, 253, 228)]
    public class AnimationClip : Clip
    {
        [ShowInInspector, OnValueChanged("OnClipChanged", "RebindTimeline")]
        public UnityEngine.AnimationClip Clip;
        
        public override int Length => Clip ? Mathf.RoundToInt(Clip.length * Timeline.FrameRate) : base.Length;

        public AnimationClip(Track track, int frame) : base(track, frame)
        {
        }
        public AnimationClip(UnityEngine.AnimationClip clip, Track track, int frame) : base(track, frame)
        {
            Clip = clip;
            EndFrame = Length + frame;
        }

#if UNITY_EDITOR

        public override string Name => Clip ? Clip.name : base.Name;
        public override bool ShowExtraPolationMode => true;
        public override ClipCapabilities Capabilities => ClipCapabilities.Resizable | ClipCapabilities.Mixable | ClipCapabilities.ClipInable;

        void OnClipChanged()
        {
            OnNameChanged?.Invoke();
        }
#endif
    }

    public class TimelineAnimationClipPlayable : TimelineClipPlayable
    {
        AnimationClip AnimationClip;
        AnimationClipPlayable ClipPlayable;

        public TimelineAnimationClipPlayable() { }

        public override void Initialize(Clip clip, Playable owner, Timeline timeline)
        {
            base.Initialize(clip, owner,  timeline);

            AnimationClip = clip as AnimationClip;
            ClipPlayable = AnimationClipPlayable.Create(timeline.PlayableGraph, AnimationClip.Clip);
            Handle.ConnectInput(0, ClipPlayable, 0);
            Handle.SetInputWeight(0, 1);
        }

        public override void SetTime(float time)
        {       
            base.SetTime(time);
            if(time > Duration)
            {
                ClipPlayable.SetTime(Duration);
            }
            else
            {
                ClipPlayable.SetTime(time);
            }
        }
    }
}